package com.zhang.common.core.utils.file;

import com.zhang.common.core.utils.PrimaryKeyUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.net.ssl.*;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.file.Files;

/**
 * @Class com.zhang.common.core.utils.file
 * @Author zhang
 * @Date 2025/9/15 10:29
 * @Description 网络文件工具类
 **/
public class NetFileUtils {

    private static final Logger logger = LoggerFactory.getLogger(NetFileUtils.class);


    /**
     * 根据文件超链接地址获取远程读取文件
     *
     * @param netUrl 文件超链接地址 - 支持http和https
     * @return File 返回超链接地址获取的文件
     */
    public static File getNetUrl(String netUrl) {
        // 判断http和https
        File file = null;
        if (netUrl.startsWith("https://")) {
            file = getNetUrlHttps(netUrl);
        } else {
            file = getNetUrlHttp(netUrl);
        }
        return file;
    }

    /**
     * 通过 http 链接获取文件流
     *
     * @param netUrl http文件链接
     * @return 返回文件链接上的文件对象
     */
    private static File getNetUrlHttp(String netUrl) {
        // 对本地文件使用 uuid 重命名
        String fileName = reloadFile(netUrl);
        // 文件对象
        File file = null;
        // 文件地址对象
        URL urlFile;
        // 输入流对象
        InputStream inStream = null;
        // 输出流对象
        OutputStream os = null;
        try {
            // 创建临时文件对象
            file = File.createTempFile("net_url", fileName);
            // 文件地址对象读取
            urlFile = new URL(netUrl);
            inStream = urlFile.openStream();
            // 文件地址数据传入指定输出流
            os = Files.newOutputStream(file.toPath());

            // 读取数据
            int bytesRead = 0;
            byte[] buffer = new byte[8192];
            // 一次写入 1 字节
            while ((bytesRead = inStream.read(buffer, 0, 8192)) != -1) {
                os.write(buffer, 0, bytesRead);
            }
        } catch (Exception e) {
            logger.error("文件地址 {} 远程图片获取错误：{}", netUrl, e.getMessage(), e);
        } finally {
            try {
                if (null != os) {
                    os.close();
                }
                if (null != inStream) {
                    inStream.close();
                }

            } catch (Exception e) {
                logger.error("获取 http 文件, 输出输入流关闭失败: {}", e.getMessage(), e);
            }
        }
        return file;
    }

    /**
     * 通过 https 链接获取文件
     *
     * @param fileUrl https链接
     * @return 返回文件链接上的文件对象
     */
    private static File getNetUrlHttps(String fileUrl) {
        // 对本地文件进行 uuid 重命名
        String file_name = reloadFile(fileUrl);
        // 文件对象
        File file = null;

        // 数据输入输出对象
        DataInputStream in = null;
        DataOutputStream out = null;
        try {
            // 文件对象
            file = File.createTempFile("net_url", file_name);

            // ssl 文件上下文对象
            SSLContext sslcontext = SSLContext.getInstance("SSL", "SunJSSE");
            // 初始化
            sslcontext.init(null, new TrustManager[]{new X509TrustUtils()}, new java.security.SecureRandom());
            URL url = new URL(fileUrl);
            HostnameVerifier ignoreHostnameVerifier = (s, sslsession) -> {
                logger.warn("警告：主机名与证书不匹配！");
                return true;
            };
            HttpsURLConnection.setDefaultHostnameVerifier(ignoreHostnameVerifier);
            HttpsURLConnection.setDefaultSSLSocketFactory(sslcontext.getSocketFactory());
            HttpsURLConnection urlCon = (HttpsURLConnection) url.openConnection();
            urlCon.setConnectTimeout(6000);
            urlCon.setReadTimeout(6000);
            int code = urlCon.getResponseCode();
            if (code != HttpURLConnection.HTTP_OK) {
                throw new Exception("文件读取失败");
            }
            // 读文件流
            in = new DataInputStream(urlCon.getInputStream());
            out = new DataOutputStream(Files.newOutputStream(file.toPath()));
            byte[] buffer = new byte[2048];
            int count = 0;
            while ((count = in.read(buffer)) > 0) {
                out.write(buffer, 0, count);
            }
            out.close();
            in.close();
        } catch (Exception e) {
            logger.error("文件地址 {} 远程图片获取错误：{}", fileUrl, e.getMessage(), e);
        } finally {
            try {
                if (null != out) {
                    out.close();
                }
                if (null != in) {
                    in.close();
                }
            } catch (Exception e2) {
                logger.error("获取 https 文件,输出输入流关闭失败：{}", e2.getMessage(), e2);
            }
        }
        return file;
    }

    /**
     * 重命名 - uuid
     *
     * @param oleFileName 文件id
     * @return String
     */
    private static String reloadFile(String oleFileName) {
        // 获取文件链接上的文件名称
        oleFileName = getFileName(oleFileName);
        // 文件判空
        if (StringUtils.isEmpty(oleFileName)) {
            return oleFileName;
        }
        // 获取后缀
        if (!oleFileName.contains(".")) {
            // 对于没有后缀的文件，直接返回重命名
            return PrimaryKeyUtils.generateId().toString();
        }
        String[] arr = oleFileName.split("\\.");
        // 根据 uuid 重命名图片
        return PrimaryKeyUtils.generateId() + "." + arr[arr.length - 1];
    }

    /**
     * 把带路径的文件地址解析为真实文件名
     * /upload/hp/xxx.mp4 解析为 xxx.mp4
     *
     * @param url 文件地址
     * @return 返回文件地址的实际文件名称
     */
    public static String getFileName(final String url) {
        // 文件地址判空
        if (StringUtils.isEmpty(url)) {
            return url;
        }
        String newUrl = url;
        // 获取地址链接参数前字符串
        newUrl = newUrl.split("[?]")[0];
        // 根据 / 将字符串划分字符串数组
        String[] bb = newUrl.split("/");
        // 返回最后一个文件名称
        return bb[bb.length - 1];
    }

}
